package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.remark.RemarkClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.remark.LikedTimesDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.entity.dto.ReplyDTO;
import com.tianji.learning.entity.mq.SignInMessage;
import com.tianji.learning.entity.po.InteractionQuestion;
import com.tianji.learning.entity.po.InteractionReply;
import com.tianji.learning.entity.query.ReplyPageQuery;
import com.tianji.learning.entity.vo.ReplyVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionReplyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.tianji.common.constants.Constant.DATA_FIELD_NAME_CREATE_TIME;
import static com.tianji.common.constants.Constant.DATA_FIELD_NAME_LIKED_TIME;

/**
 * <p>
 * 互动问题的回答或评论 服务实现类
 * </p>
 *
 * @author lemon
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {

    private final InteractionQuestionMapper interactionQuestionMapper;

    private final UserClient userClient;

    private final RemarkClient remarkClient;

    private final RabbitMqHelper mqHelper;

    /**
     * 新增互动回答或评论
     *
     * @param dto
     */
    @Transactional
    @Override
    public void addInteractionReply(ReplyDTO dto) {
        Long userId = UserContext.getUser();
        InteractionReply interactionReply = BeanUtils.copyBean(dto, InteractionReply.class);
        interactionReply.setUserId(userId);
        this.save(interactionReply);

        // 3.累加评论数或者累加回答数
        // 3.1.判断当前回复的类型是否是回答
        boolean isAnswer = dto.getAnswerId() == null;
        // isAnswer为null的话就回答
        if (!isAnswer) {
            // 3.2.是评论，则需要更新上级回答的评论数量
            this.lambdaUpdate()
                    // 这个reply这个里面就是有回答和评论
                    .setSql("reply_times = reply_times + 1")
                    .eq(InteractionReply::getId, dto.getAnswerId())
                    .update();


        }

        // 根据answerId查询问题
        InteractionQuestion question = interactionQuestionMapper.selectById(dto.getQuestionId());
        // 下面就修改问题表中的状态、 最近一次回答、回答数量
        interactionQuestionMapper.update(question, Wrappers.<InteractionQuestion>lambdaUpdate()
                // 这个是最新回答的id
                .set(isAnswer, InteractionQuestion::getLatestAnswerId, interactionReply.getAnswerId())
                // 这个有原语操作
                .setSql(isAnswer, "answer_times = answer_times + 1")
                // 这个问题是最新回答的时间
                // 学生提交的状态为未查看这样就可以在学生端显示未查看
                .set(dto.getIsStudent(), InteractionQuestion::getStatus, QuestionStatus.UN_CHECK.getValue())
//                .set(!dto.getIsStudent(), InteractionQuestion::getStatus, QuestionStatus.CHECKED.getValue())
                .eq(InteractionQuestion::getId, dto.getQuestionId()));

        // TODO 加积分
        if (dto.getIsStudent()) {
            // TODO 加积分
            // TODO 加积分
            SignInMessage signInMessage = new SignInMessage();
            signInMessage.setUserId(userId);
            signInMessage.setPoints(5);

            // 添加积分消息
            mqHelper.send(
                    MqConstants.Exchange.LEARNING_EXCHANGE,
                    MqConstants.Key.WRITE_NOTE,
                    signInMessage);

        }
    }

    /**
     * 分页查询互动回答或评论-用户端管理端公用
     *
     * @param query
     * @param isAdmin
     * @return
     */
    @Override
    public PageDTO<ReplyVO> queryReplyPage(ReplyPageQuery query, boolean isAdmin) {
        Long answerId = query.getAnswerId(); // 回答id
        Long questionId = query.getQuestionId(); // 问题id
        // 一个是评论一个是回答
        if (answerId == null && questionId == null) {
            throw new BizIllegalException("回答id和问题id不能同时为空");
        }
        // 看是否是回答
        // 只查询回答
        boolean isQueryAnswer = questionId != null; // 为true就是回答
        Page<InteractionReply> page = this.lambdaQuery()

                .eq(isQueryAnswer, InteractionReply::getQuestionId, questionId)
                // 如果是回答的话就没有父id 评论的话就有父id
                .eq(InteractionReply::getAnswerId, isQueryAnswer ? 0L : answerId)
                .eq(!isAdmin, InteractionReply::getHidden, false)
                .page(query.toMpPage(
                        // 先根据点赞数排序，点赞数相同，再按照创建时间排序
                        new OrderItem(DATA_FIELD_NAME_LIKED_TIME, false),
                        new OrderItem(DATA_FIELD_NAME_CREATE_TIME, true)
                ));
        List<InteractionReply> records = page.getRecords();
        if (records.isEmpty()) {
            return PageDTO.empty(page);
        }

        // 3.数据处理，需要查询：提问者信息、回复目标信息、当前用户是否点赞
        Set<Long> userIds = new HashSet<>();
        // 根据回答id查询回复
        // 这个是来看当前用户是否点赞这个回答
        Set<Long> answerIds = new HashSet<>();
        // 也就是他回复的那个评论的id
        Set<Long> targetReplyIds = new HashSet<>();
        for (InteractionReply r : records) {
            // 如果不是匿名的话就把用户id加进去
            // 如果是管理员的话就不用判断了
            if (!r.getAnonymity() || isAdmin) {
                // 非匿名 才需要查询用户信息
                userIds.add(r.getUserId());
            }
            targetReplyIds.add(r.getTargetReplyId());
            answerIds.add(r.getId());
        }

        // TODO 调用点赞服务查询当前回答或者评论的点赞数
        // targetRelyIds
        targetReplyIds.remove(0L);
        if (targetReplyIds.size() > 0) {
            // 看回复的那个评论的是否匿名
            List<InteractionReply> targetReplies = listByIds(targetReplyIds);
            Set<Long> targetUserIds = targetReplies.stream()
                    .filter(item -> {
                        return !item.getAnonymity() || isAdmin;
                    })
//                    .filter(Predicate.not(InteractionReply::getAnonymity).or(r -> isAdmin))
                    .map(InteractionReply::getUserId)
                    .collect(Collectors.toSet());
            userIds.addAll(targetUserIds);
        }
        // 3.3.查询用户
        Map<Long, UserDTO> userMap = new HashMap<>(userIds.size());
        if (userIds.size() > 0) {
            List<UserDTO> users = userClient.queryUserByIds(userIds);
            userMap = users.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));
        }

        // TODO 3.4.查询用户点赞状态
        Set<Long> bizLiked = remarkClient.getLikesStatus(answerIds);

        List<ReplyVO> replyVOList = new ArrayList<>();
        // 下面就是封装vo
        for (InteractionReply record : records) {
            ReplyVO replyVO = BeanUtils.copyBean(record, ReplyVO.class);
            // 4.2.回复人信息
            if (!record.getAnonymity() || isAdmin) {
                UserDTO userDTO = userMap.get(record.getUserId());
                if (userDTO != null) {
                    replyVO.setUserIcon(userDTO.getIcon() == null ? "" : userDTO.getIcon());
                    replyVO.setUserName(userDTO.getName() == null ? "" : userDTO.getName());
                    replyVO.setUserType(userDTO.getType() == null ? 1 : userDTO.getType());
                }
            }
            // 4.3.如果存在评论的目标，则需要设置目标用户信息
            if (record.getTargetReplyId() != null) {
                UserDTO targetUser = userMap.get(record.getTargetUserId());
                if (targetUser != null) {
                    replyVO.setTargetUserName(targetUser.getName() == null ? "" : targetUser.getName());
                }

            }
            // TODO 4.4.点赞状态，也就是是否点赞
            replyVO.setLiked(bizLiked.contains(record.getId()));
            replyVOList.add(replyVO);
        }

        return PageDTO.of(page, replyVOList);
    }

    /**
     * 点赞
     *
     * @param dto
     */
    @Transactional
    @Override
    public void updateLikeRecord(List<LikedTimesDTO> dto) {
        if (dto.isEmpty()) {
            return;
        }
        // 消息转po
        List<InteractionReply> list = new ArrayList<>();

        for (LikedTimesDTO likedTimesDTO : dto) {
            InteractionReply interactionReply = new InteractionReply();
            interactionReply.setId(likedTimesDTO.getBizId());
            interactionReply.setLikedTimes(likedTimesDTO.getLikedTimes());
            list.add(interactionReply);
        }

        // 批量更新
        this.updateBatchById(list);

    }


    @Override
    public void hiddenReply(Long id, Boolean hidden) {
        // 先查询
        InteractionReply reply = this.getById(id);
        if (reply == null) {
            throw new BizIllegalException("回复不存在");
        }
        reply.setHidden(hidden);
        this.updateById(reply);
    }
}
